AS3でグラフィカルプログラミング#3
ActionScript3.0で図形を描画するための方法について解説していきます。
- この記事の対象:FlashまたはFlexに触れたことがある方。
- 必要な開発環境:Flash、 FlashBuilder、 FlashDevelop等の、ActionScript3.0の記述と実行ができる環境。
今回は、座標計算について解説します。
使用するクラスと単位
計算の解説に入る前に、使用するクラスと単位について簡単に説明しておきます。
Pointクラス
Pointクラスは、x座標とy座標の値を保持するクラスです。座標計算を行うのに役立つ様々な機能を持っています。
Mathクラス
Mathクラスは、様々な計算に使用する一般的な数学関数や定数を持ったクラスです。
ラジアン
前回のMatrixの項でも少し出てきましたが、AS3では、角度の単位は主にラジアン(rad)を使用します。1radは、半径と弧の長さが等しくなる角度です。円周の長さは半径*2πであるため、度数法の360°は2πradとなります。
//度数をラジアンに変換 radian = degree / 180 * Math.PI; //ラジアンを度数に変換 degree = radian * 180 / Math.PI;
基本的な計算
基本的な座標や角度の計算方法を解説します。
座標の加算減算
addとsubtractを使用することで、座標同士の加算減算が行えます。加算減算によって算出される座標イメージを以下の図に示します。
//x=400, y=200の座標p1を作成します。 var p1:Point = new Point(400, 200); //x=200, y=25の座標p2を作成します。 var p2:Point = new Point(200, 25); //p1にp2を加算した座標p3を求めます。 var p3:Point = p1.add(p2); //p1からp2を減算した座標p4を求めます。 var p4:Point = p1.subtract(p2);
角度を求める
座標値から角度を算出するには、Math.atan2が便利です。引数の順序がy、xの順になっている事に気をつけてください。算出される値の単位はラジアンです。ここで算出される角度は、指定座標の原点からの角度であるため、特定の座標からの角度を算出したい場合は前述のsubtractを併用します。リファレンスには、X軸から反時計回りで計測するとありますが、AS3の座標系は下方向がYの正となっているため、実際は時計回りで考えた方が分かりやすいと思います。
//x=100 y=100√3の座標p1を作成します。 var p1:Point = new Point(100, 100 * Math.sqrt(3)); //1の原点からの角度を算出します。 var rad1:Number = Math.atan2(p1.y, p1.x); //ラジアンと度数を出力します。 trace(rad1, rad1 / Math.PI * 180);//1.0471975511965976 60 //x=400, y=0の座標p2を作成します。 var p2:Point = new Point(400, 0); //p1から見たp2の相対座標を求めます。 var p3:Point = p2.subtract(p1); //p1から見たp2の角度を算出します。 var rad2:Number = Math.atan2(p3.y, p3.x); //ラジアンと度数を出力します。 trace(rad2, rad2 / Math.PI * 180);//-0.5235987755982988 -30
距離を求める
lengthで、原点からその座標までの距離を取得できます。また、任意の二点間の距離を求めるには、distanceを使用します。
//x=100 y=100√3の座標p1を作成します。 var p1:Point = new Point(100, 100 * Math.sqrt(3)); //原点からp1の距離を出力します。 trace(p1.length);//200 //x=400, y=0の座標p2を作成します。 var p2:Point = new Point(400, 0); //p1とp2の間の距離を出力します。 trace(Point.distance(p1, p2), 200*Math.sqrt(3));//346.41016151377545 = 200√3
角度と距離から座標を求める
polarで、原点からの角度と距離を指定して座標を算出できます。addと併用することで、原点だけではなく任意の座標を基準点とした座標を求める事もできます。
//原点から60°方向に200pxの座標p1を求めます。 var p1:Point = Point.polar(200, 60 / 180 * Math.PI); //p1から-30°方向に100pxの座標p2を求めます。 var p2:Point = p1.add(Point.polar(100, -30 / 180 * Math.PI));
二点間を結ぶ線上の座標を求める
二点間を結ぶ線上の位置の座標値を求めるには、interpolateを使用します。始点と終点の間の位置を0~1の比率で指定します。0を指定すると終点、1を指定すると始点と等しい座標が返ります。
//x=200 y=0の座標p1を作成します。 var p1:Point = new Point(200, 0); //x=0 y=200の座標p2を作成します。 var p2:Point = new Point(0, 200); //p1~p2上を0.4:0.6に分割する座標を求めます。 var p3:Point = Point.interpolate(p1, p2, 0.6);
応用問題
これらのパターンを組み合わせて、以下の問題を解いてみます。
三点間を結ぶ線の角度
開始点と終了点を経由点から見た相対座標に変換した上で角度を求めます。
/** * 三点間の角度を求めます。 * @param start 開始点です。 * @param via 経由点です。 * @param end 終了点です。 * @return 三点間の角度です。 */ private function get3PointDegree(start:Point, via:Point, end:Point):Number { //開始点と終了点のいずれかが経由点と等しい場合、0を返します。 if(Point.distance(start, via) == 0 || Point.distance(via, end) == 0) { return 0; } //経由点から見た開始点と終了点の相対座標を求めます。 var p1:Point = start.subtract(via); var p2:Point = end.subtract(via); //上で求めた座標の原点からの角度を求めます。 var r1:Number = Math.atan2(p1.y, p1.x); var r2:Number = Math.atan2(p2.y, p2.x); //三点間の角度を求めます。 var r:Number = r2 - r1; //-πからπの間の値に変換します。 if(r > Math.PI) { r -= Math.PI * 2; } else if(-Math.PI > r) { r += Math.PI * 2; } //度数に変換します。 return r / Math.PI * 180; }
二点間を結ぶ線と互いの中心点で直角に交わる、同じ長さの線の始点座標と終点座標
二点間の中心座標と角度を求め、そこから90°回転させた座標を求めます。
/** * 二点間を結ぶ線と互いの中心点で直角に交わる、同じ長さの線の開始点座標と終了点座標を求めます。 * @param start 開始点です。 * @param end 終了点です。 * @return 開始点と終了点の配列 */ private function getRightAngleLine(start:Point, end:Point):Array { //開始点と終了点が等しい場合は、引数をそのまま返します。 if(start.equals(end)) { return [start, end]; } //交差する座標を求めます。 var crossPoint:Point = Point.interpolate(start, end, 0.5); //交差点から、開始点と終了点までの距離を求めます。 var length:Number = Point.distance(start, end) / 2; //開始点から見た終了点の相対座標を求めます。 var p1:Point = end.subtract(start); //開始点から見た終了点の角度を求めます。 var r1:Number = Math.atan2(p1.y, p1.x); //90°傾けます。 r1 += Math.PI / 2; //交差点から見た、交差線の開始点の相対座標を求めます。 var crossStart:Point = Point.polar(length, r1); //絶対座標に変換します。 crossStart = crossStart.add(crossPoint); //交差点から見た、交差線の終了点の相対座標を求めます。 var crossEnd:Point = Point.polar(-length, r1); //絶対座標に変換します。 crossEnd = crossEnd.add(crossPoint); return [crossStart, crossEnd]; }
PointクラスとMathクラスの機能を活用することで、手計算を行うときのような複雑な計算式を大幅に省略できることがお分かりいただけたかと思います。
今回は、座標計算について解説しました。今回で基礎的な内容は終了です。以降は、ActionScriptの面白い機能を使ったグラフィカルなプログラムを紹介していく予定です。